// CascadeClassifier.cpp: implementation of the CCascadeClassifier class.
//
//////////////////////////////////////////////////////////////////////

#include "ASample.h"
#include "AdaBClassifier.h"
#include "CascadeClassifier.h"
#include "PonPoff.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CCascadeClassifier::CCascadeClassifier()
{
	strcpy(m_strID, "Cascade");
}

CCascadeClassifier::~CCascadeClassifier()
{
	Clear();
}

void CCascadeClassifier::Clear()
{
	int nClassifiers = m_vpClassifiers.size();
	for (int i = 0; i < nClassifiers; i ++)
	{
		delete m_vpClassifiers[i];
	}
}

///
///
///

float CCascadeClassifier::Classify(CASample *pSample, const char flag)
{
	int		i,nClassifiers = m_vpClassifiers.size();
	float	p;
	double	t;

	if (flag == DETECT_TEXT)
	{
		double e = 0;
		for (i = 0; i < nClassifiers; i ++)
		{
			CAClassifier *pClassifier = m_vpClassifiers[i];
			p = pClassifier->Classify(pSample, flag);
			if (p < 0)
				return 0;
			t = exp(p+p);
			e += t/(99+t);
			if ((e + nClassifiers-i-1)/nClassifiers < 0.95)
				return 0;
		}
		return e/nClassifiers;
	}
	else if (flag == DETECT_FACE)
	{
		for (i = 0; i < nClassifiers; i ++)
		{
			CAClassifier *pClassifier = m_vpClassifiers[i];
			p = pClassifier->Classify(pSample, flag);
			if (p < 0.005)
				return p;
		}

		return 1.0f;
	}

	return 0;
}

///
bool CCascadeClassifier::LoadFromFile(const char *strFileName)
{
	FILE *fp = fopen(strFileName, "rb");
	if (fp == NULL)
		return false;

	// clear the current cascade
	Clear();

	LoadFromFile(fp);

	fclose(fp);

	return true;
}
	
void CCascadeClassifier::LoadFromFile(FILE *fp)
{
	// Read classifier ID
	fread(&m_strID, sizeof(char), 20, fp);
	// read IDs of features used in the classifier
	int nFeaID;
	fread(&nFeaID, sizeof(int), 1, fp);
	m_vFeaID.resize(nFeaID);
	int i; 
	for (i = 0; i < nFeaID; i ++)
	{
		CFeaID &fid = m_vFeaID[i];
		fread(fid.strFeaName, sizeof(char), 2, fp);
		fread(&fid.nFeaIdx, sizeof(int), 1, fp);
	}

	//read number of classifiers
	int nClassifiers;
	fread(&nClassifiers, sizeof(int), 1, fp);
	nClassifiers-=0;
	m_vpClassifiers.resize(nClassifiers);
	//read each of the classifiers
	for (i = 0; i < nClassifiers; i ++)
	{
		char strID[20];
		fread(strID, sizeof(char), 20, fp);
		fseek(fp, -20L, SEEK_CUR);
		
		CAClassifier *pClassifier;
		if (strcmp(strID, "PonPoff") == 0){
			pClassifier = new CPonPoff();
		}else if (strcmp(strID, "AdaBoost") == 0){
			pClassifier = new CAdaBClassifier();
		}else{ 
			pClassifier = NULL; // Siyuan: suppress compiling error
		}

		pClassifier->LoadFromFile(fp);
		m_vpClassifiers[i] = pClassifier;
	}
}

bool CCascadeClassifier::SaveToFile(const char *strFileName)
{
	FILE *fp = fopen(strFileName, "wb");
	if (fp == NULL)
		return false;

	SaveToFile(fp);

	fclose(fp);

	return true;
}

void CCascadeClassifier::SaveToFile(FILE *fp)
{
	// Write classifier ID
	fwrite(&m_strID, sizeof(char), 20, fp);
	// Write IDs of features used in the classifier
	int nFeaID = m_vFeaID.size();
	fwrite(&nFeaID, sizeof(int), 1, fp);
	int i;
	for ( i = 0; i < nFeaID; i ++)
	{
		CFeaID &fid = m_vFeaID[i];
		fwrite(fid.strFeaName, sizeof(char), 2, fp);
		fwrite(&fid.nFeaIdx, sizeof(int), 1, fp);
	}

	//write number of classifiers
	int nClassifiers = m_vpClassifiers.size();
	fwrite(&nClassifiers, sizeof(int), 1, fp);
	//write each of the classifiers
	for (i = 0; i < nClassifiers; i ++)
	{
		CAClassifier *pClassifier = m_vpClassifiers[i];
		pClassifier->SaveToFile(fp);
	}
}

void CCascadeClassifier::AddClassifier(CAClassifier *pClassifier)
{
	m_vpClassifiers.push_back(pClassifier);
}

int CCascadeClassifier::GetNumOfLayers()
{
	return m_vpClassifiers.size();
}
